package com.sky.base.security.utils;

import com.sky.base.constant.CacheConstants;
import com.sky.base.constant.Constants;
import com.sky.base.security.pojo.LoginUser;
import com.sky.exception.BaseException;
import com.sky.utils.JwtUtil;
import com.sky.utils.RedisCache;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/8/13
 */
@Component
@Slf4j
public class TokenUtil {

    // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;

    // 令牌有效期（默认30分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;

    @Autowired
    private RedisCache redisCache;

    /**
     * 获取redis中的login对象
     *
     * @param userId
     * @return
     */
    public String getRedisTokenKey(String userId) {
        return CacheConstants.LOGIN_TOKEN_KEY + userId;

    }

    /**
     * 获取token值
     *
     * @param request
     * @return
     */
    public String getToken(HttpServletRequest request) {
        String token = request.getHeader(Constants.TOKEN);
        if (StringUtils.hasText(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }

    /**
     * 通过token获取id，通过redis中的key获取loginUser对象
     *
     * @param request
     * @return
     */
    public LoginUser getLoginUser(HttpServletRequest request) {
        String token = getToken(request);
        if (StringUtils.hasText(token)) {
            try {
                Claims claims = JwtUtil.parse(token);
                String userId = String.valueOf(claims.get(Constants.JWT_ID));
                String userKey = getRedisTokenKey(userId);
                LoginUser loginUser = redisCache.getCacheObject(userKey);
                return loginUser;
            } catch (Exception e) {

            }

        }
        return null;

    }


    /**
     * 删除redis中的用户信息
     *
     * @param token
     */
    public void delLoginUser(String token) {
        if (StringUtils.hasText(token)) {
            String userKey = getRedisTokenKey(token);
            redisCache.deleteObject(userKey);
        }
    }

    /**
     * 使用JwtUtil创建token
     *
     * @param loginUser
     * @return
     */
    public String createToken(LoginUser loginUser) {
        Long id = loginUser.getUser().getId();
        Map<String, Object> map = new HashMap<>();
        // 将loginUser信息存入redis中
        refreshToken(loginUser);
        map.put(Constants.JWT_ID, id);
        String token = Constants.TOKEN_PREFIX + JwtUtil.jwt(map);
        return token;
    }

    /**
     * 设置用户身份信息
     */
    public void setLoginUser(LoginUser loginUser) {
        if (!Objects.isNull(loginUser)) {
            refreshToken(loginUser);
        }
    }

    /**
     * 验证令牌有效期，相差不足20分钟，自动刷新缓存
     * @param loginUser
     */
    public void verifyToken(LoginUser loginUser) {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
            refreshToken(loginUser);
        }
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser){
        loginUser.setExpireTime(System.currentTimeMillis() + expireTime * MILLIS_MINUTE);
        // 根据uuid将loginUser缓存
        String userKey = getRedisTokenKey(loginUser.getUser().getId().toString());
        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }


}
